package com.hoshiicloud.payment.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.hoshiicloud.common.constant.enumeration.Channel;
import com.hoshiicloud.common.rpc.Response;
import com.hoshiicloud.common.utils.DigestUtils;
import com.hoshiicloud.payment.Paylist;
import com.hoshiicloud.payment.Payment;
import com.hoshiicloud.payment.Platform;
import com.hoshiicloud.payment.WeixinPayConfig;
import com.hoshiicloud.payment.config.PayConfig;
import com.hoshiicloud.payment.feign.UserFeignService;
import com.hoshiicloud.payment.param.CallBackRequest;
import com.hoshiicloud.payment.sdk.wxpay.WXPayConstants;
import com.hoshiicloud.payment.sdk.wxpay.WXPayUtil;
import com.hoshiicloud.payment.service.CallBackService;
import com.hoshiicloud.payment.service.PaylistService;
import com.hoshiicloud.payment.service.PaymentService;
import com.hoshiicloud.payment.util.TensoonUtil;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * @Author:campchen
 * @Date:Created in 上午 11:21 2019/7/16
 * @PACKAGENAME com.hoshiicloud.payment.service.impl
 * @Description
 */
@Slf4j
@Service
public class CallBackServiceImpl implements CallBackService {

    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Autowired
    private PaylistService paylistService;
    @Autowired
    private UserFeignService platformService;
    @Autowired
    private PaymentService paymentService;

    @Override
    public String wxPayCallBack(String str) {
        Map<String, String> successMap = new HashMap<String, String>();
        String successXml = null;
        try {
            log.info("微信收款回调参数:" + str);
            Map<String, String> reqData = WXPayUtil.xmlToMap(str);
            if ("SUCCESS".equals(reqData.get("return_code"))) {
                //根据商户订单号查询对应商户密钥

                String merOrderId = reqData.get("out_trade_no");
                String outTradeNo = reqData.get("transaction_id");
                QueryWrapper<Paylist> queryWrapper = new QueryWrapper<Paylist>();
                queryWrapper.lambda().eq(Paylist::getId, merOrderId);
                String cacheKey=merOrderId;
                List<Paylist> list = paylistService.getByParam(queryWrapper,cacheKey);
                // if(list.size()==0){
                if (CollectionUtils.isEmpty(list)) {
                    log.error("订单不存在");
                    successMap.put("return_code", "FAIL");
                    successMap.put("return_msg", "订单不存在");
                    successXml = WXPayUtil.mapToXml(successMap);
                    return successXml;
                }
                Paylist order = list.get(0);
                Platform platform = platformService.getById(order.getPlatformId()).getData();
                if (platform == null) {
                    log.error("订单商户不存在");
                    successMap.put("return_code", "FAIL");
                    successMap.put("return_msg", "订单商户不存在");
                    successXml = WXPayUtil.mapToXml(successMap);
                    return successXml;
                }
                //根据商户号和渠道获取商户配置
                queryWrapper = new QueryWrapper();
                queryWrapper.eq("platformid", platform.getId());
                queryWrapper.eq("pay_code", Channel.WEIXIN.getPayCode());
                Payment payment = paymentService.getByParam(queryWrapper);
                if (payment == null) {
                    log.error("支付信息未配置");
                    successMap.put("return_code", "FAIL");
                    successMap.put("return_msg", "支付信息未配置");
                    successXml = WXPayUtil.mapToXml(successMap);
                    return successXml;
                }
                //签名验证
                WeixinPayConfig weixinPayConfig = JSON.parseObject(payment.getPayConfig(), WeixinPayConfig.class);
                String key = weixinPayConfig.getAppKey();
                WXPayConstants.SignType signType=null;
                if(PayConfig.debug){
                    signType= WXPayConstants.SignType.MD5;
                }
                else{
                    signType= WXPayConstants.SignType.HMACSHA256;
                }
                String sign = WXPayUtil.generateSignature(reqData, key,signType);
                log.debug("返回签名:" + reqData.get("sign"));
                log.debug("我方签名:" + sign);
                if (reqData.get("sign").equals(sign)) {
                    log.debug("验签结果：通过");
                } else {
                    log.info("验签结果：不通过");
                    successMap.put("return_code", "FAIL");
                    successMap.put("return_msg", "签名不正确");
                    successXml = WXPayUtil.mapToXml(successMap);
                    return successXml;
                }
                //TODO 不为可支付状态时接收到支付回调的处理

                //分转为元
                BigDecimal amount = new BigDecimal(reqData.get("total_fee")).divide(new BigDecimal(100)).setScale(2, RoundingMode.DOWN);
                //获取支付时间
                DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
                LocalDateTime payTime = LocalDateTime.parse(reqData.get("time_end"), df);
                CallBackRequest callBackRequest = new CallBackRequest(amount, merOrderId, outTradeNo, payTime);
                Response result = paylistService.paymentProcess(callBackRequest);
                if (result.isSuccess()) {
                    //组装xml返回
//                    Map<String, String> successMap = new HashMap<String, String>();
                    successMap.put("return_code", "SUCCESS");
                    successMap.put("return_msg", "OK");
                    successXml = WXPayUtil.mapToXml(successMap);
                    //TensoonUtil.responseWriteString(response, successXml);
                    log.debug("处理完毕,成功返回");
                    log.debug("微信支付回调成功");
                    return successXml;
                } else {
                    log.error("微信支付回调处理异常:" + result.getMsg());
                    successMap.put("return_code", "FAIL");
                    successMap.put("return_msg", "微信支付回调处理异常");
                    successXml = WXPayUtil.mapToXml(successMap);
                    return successXml;
                }
            } else {
                //回调信息失败
                log.debug("微信支付回调失败:" + reqData.get("return_msg"));
                successMap.put("return_code", "FAIL");
                successMap.put("return_msg", "微信支付回调失败");
                successXml = WXPayUtil.mapToXml(successMap);
                return successXml;
            }
        } catch (Exception e) {
            log.error("微信支付回调异常：", e);
            return successXml = "{\n" +
                    "\t\"return_code\": \"FAIL\",\n" +
                    "\t\"return_msg\": \"微信支付回调异常\"\n" +
                    "}";
        }
    }

    @Override
    public String wxRefundCallBack(String str) {
        Map<String, String> successMap = new HashMap<>();
        try {
            log.info("微信退款回调参数:" + str);
            Map<String, String> reqData = WXPayUtil.xmlToMap(str);
            if ("SUCCESS".equals(reqData.get("return_code"))) {
                //根据appid查找商户配置
                /**
                 * 解密步骤如下：
                 * （1）对加密串A做base64解码，得到加密串B
                 * （2）对商户key做md5，得到32位小写key* ( key设置路径：微信商户平台(pay.weixin.qq.com)-->账户设置-->API安全-->密钥设置 )
                 *
                 * （3）用key*对加密串B做AES-256-ECB解密（PKCS7Padding）
                 */
                String appId = reqData.get("appid");
                QueryWrapper queryWrapper = new QueryWrapper();
                //因商户参数包含在json字符串内,此处需使用mysql的locate函数进行查询，故使用last直接拼接条件sql
                queryWrapper.last("where locate (\"" + appId + "\",pay_config) ");
                Payment config = paymentService.getByParam(queryWrapper);
                if (config == null) {
                    log.error("支付信息未配置");
                    successMap.put("return_code", "FAIL");
                    successMap.put("return_msg", "支付信息未配置");
                    return WXPayUtil.mapToXml(successMap);
                }
                WeixinPayConfig weixinPayConfig = JSON.parseObject(config.getPayConfig(), WeixinPayConfig.class);
                String appKey = weixinPayConfig.getAppKey();
                String decryptionKey = DigestUtils.md5(appKey).toLowerCase();
                String encryptedData = reqData.get("req_info");
                String data = TensoonUtil.decryptData(encryptedData, decryptionKey.getBytes());
                if (StringUtils.isBlank(data)) {
                    log.error("解密报文异常");
                    successMap.put("return_code", "FAIL");
                    successMap.put("return_msg", "解密报文异常");
                    return WXPayUtil.mapToXml(successMap);
                }
                Map<String, String> dataMap = WXPayUtil.xmlToMap(data);
                log.info("解密后的明文:" + dataMap);
                //组装处理参数
                //分转为元
                BigDecimal amount = new BigDecimal(dataMap.get("total_fee")).divide(new BigDecimal(100)).setScale(2, RoundingMode.DOWN);
                //获取退款时间
                DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
                String successTime=dataMap.get("success_time");
                LocalDateTime payTime=null;
                if (StringUtils.isNotBlank(successTime)) {
                     payTime = LocalDateTime.parse(successTime, df);
                }else{
                     payTime = LocalDateTime.now();
                }

                CallBackRequest callBackRequest = new CallBackRequest(amount, dataMap.get("out_refund_no"), dataMap.get("refund_id"), payTime);
                Response result = paylistService.refundProcess(callBackRequest);
                if (result.isSuccess()) {
                    //组装xml返回
                    successMap.put("return_code", "SUCCESS");
                    successMap.put("return_msg", "OK");
                    log.error("处理完毕,成功返回");
                    log.error("微信退款回调成功");
                    return WXPayUtil.mapToXml(successMap);
                    //TensoonUtil.responseWriteString(response, successXml);

                } else {
                    log.error("微信退款回调失败:" + result.getMsg());
                    successMap.put("return_code", "FAIL");
                    successMap.put("return_msg", "微信退款回调失败");
                    return WXPayUtil.mapToXml(successMap);
                }
            } else {
                //回调信息失败
                log.error("微信退款回调失败:" + reqData.get("return_msg"));
                successMap.put("return_code", "FAIL");
                successMap.put("return_msg", "微信退款回调失败");
                return WXPayUtil.mapToXml(successMap);
            }
        } catch (Exception e) {
            log.error("微信退款回调异常：", e);
            return "{\n" +
                    "\t\"return_code\": \"FAIL\",\n" +
                    "\t\"return_msg\": \"微信退款回调异常\"\n" +
                    "}";
        }
    }
}
